Skip to content

The wallet was connected. It was on the wrong chain. - #230

Merged
0xward merged 1 commit into
mainfrom
claude/nullstate-onchain-text-q6g2a3
Aug 3, 2026
Merged

The wallet was connected. It was on the wrong chain.#230
0xward merged 1 commit into
mainfrom
claude/nullstate-onchain-text-q6g2a3

Conversation

@0xward

@0xward 0xward commented Aug 3, 2026

Copy link
Copy Markdown
Owner

The owner tested in the OKX in-app browser: auto-connect worked, and every purchase said "Wallet not connected".

The message was a lie. One line inside wagmi decides it (@wagmi/core/actions/getConnectorClient):

if (assertChainId && connectorChainId !== chainId)
  throw new ConnectorChainMismatchError(...)

The app asks for a Celo-pinned client — useWalletClient({ chainId: CELO_CHAIN_ID }) — so on any other chain that throws, useWalletClient swallows it into data: undefined, and every payment path hits its !walletClient guard and reports a connection problem to somebody whose wallet was connected and one tap from working.

OKX opens on its own default chain. MiniPay is Celo-only and could never reach this state, which is why it survived to the first browser-wallet test.

The part that stings: switchToCelo already existed — plumbed through the bridge, out through WalletProvider — and had no caller anywhere in the app. The escape hatch was built and never fitted.

Auto-switch, immediately

The owner's call, and the right one before a listing review: the moment a connection lands on a non-Celo chain, the wallet is asked to switch. Not deferred to the first purchase — a reviewer who opens the shop and sees an error has already formed their opinion.

Asked once per chain, via a ref. Asking on every render is a popup loop, which is worse than the bug it fixes. Declining leaves the bar up; moving the wallet to another chain arms one fresh attempt.

The message stops lying

All three signing paths in the island go through one assertReady(), and so do the two hooks that guard on walletClient themselves — the Season Pass mint (the exact screen reported) and the reward claim, which has the identical shape:

Wrong network — NullState runs on Celo. Switch your wallet to Celo and try again.

And a way out

WrongNetworkBar renders on the three screens that can spend — Marketplace, Crafting, Season Pass — only when connected to the wrong chain, with a Switch to Celo button wired to the switchToCelo that never had a caller.

It uses switchChainAsync, so the pending state means something; the fire-and-forget variant resolves instantly whether the wallet agreed or not. A wallet that cannot switch at all (some in-app browsers pin their chain) is told to pick Celo by hand, rather than given a button that silently does nothing.

Nothing here can reach MiniPay. It is Celo-only, so wrongNetwork is false there and the bar returns null. check:copy still passes — the copy names Celo and avoids the banned phrase.

Testing

✓ 20/20 test:network (new, npm run test:network)
✓ tsc clean   ✓ build 142/242 kB (unchanged)
✓ check:copy  ✓ check:cssvars  ✓ lint 35

One assertion runs against wagmi's own source, so a future upgrade that changes this behaviour fails here rather than in a player's purchase.

What is not covered, stated plainly: no browser test simulates a wrong-chain wallet, because the sandbox has no wallet at all. The assertions are source-level.

Adjacent, not fixed here

Players who signed in with Google/email still cannot buy — their account address is a hash and cannot sign. That is the two-layer design, not a regression, but the Privy gate makes it a larger group than before.


Generated by Claude Code

OWNER, testing in the OKX in-app browser: *"posisi auto connect tapi gabisa mint
pass dan buy ada tulisan 'wallet not connected', itu kenapa?"*

Because the message was a lie. One line inside wagmi decides it
(@wagmi/core/actions/getConnectorClient):

    if (assertChainId && connectorChainId !== chainId)
      throw new ConnectorChainMismatchError(...)

The app asks for a Celo-pinned client — useWalletClient({chainId: CELO}) — so on
ANY other chain that throws, useWalletClient swallows it into `data: undefined`,
and every payment path hits its `!walletClient` guard and reports a connection
problem to somebody whose wallet was connected and one tap from working. OKX
opens on its own default chain. MiniPay is Celo-only and could never reach it,
which is why this survived to the first browser-wallet test.

The part that stings: `switchToCelo` already existed, plumbed through the bridge
and out to WalletProvider — and had no caller anywhere in the app. The escape
hatch was built and never fitted.

AUTO-SWITCH, IMMEDIATELY. The owner's call, and the right one for a listing
review: *"itu bener2 autoconnect dan autoswitch jaringan ke celo dr awal login
dengan wallet."* The moment a connection lands on a non-Celo chain the wallet is
asked to switch — not deferred to the first purchase, because a reviewer who
opens the shop and sees an error has already formed their opinion.

Asked ONCE per chain, via a ref. Asking on every render is a popup loop, which
is worse than the bug it fixes. Declining leaves the bar up; moving the wallet
to another chain arms one fresh attempt.

THE MESSAGE STOPS LYING. All three signing paths in the island go through one
assertReady(), and the two hooks that guard on walletClient themselves — the
Season Pass mint, which is the exact screen reported, and the reward claim,
which has the identical shape — say the same thing: wrong network, NullState
runs on Celo.

AND A WAY OUT. WrongNetworkBar renders on the three screens that can spend,
only when connected to the wrong chain, with a Switch to Celo button wired to
the switchToCelo that never had a caller. It uses switchChainAsync so the
pending state means something; the fire-and-forget variant resolves instantly
whether the wallet agreed or not. A wallet that cannot switch at all gets told
to pick Celo by hand rather than a button that silently does nothing.

Nothing here can reach MiniPay: it is Celo-only, so wrongNetwork is false there
and the bar returns null. check:copy still passes — the copy names Celo and
avoids the banned phrase.

Verified: 20/20 test:network, tsc clean, build unchanged at 142/242 kB,
check:copy, check:cssvars, lint 35.

What is NOT covered, stated plainly: no browser test simulates a wrong-chain
wallet, because the sandbox has no wallet at all. The assertions are
source-level, including one against wagmi's own source so a future upgrade that
changes this behaviour fails here rather than in a player's purchase.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017A764RdnwpyWnG7uCNhMiQ
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nullstate Ready Ready Preview Aug 3, 2026 6:40am

@0xward
0xward merged commit f8e8f11 into main Aug 3, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant